package org.apache.solr.ocean.update;

import java.io.IOException;
import java.net.URL;

import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.SolrCore;
import org.apache.solr.ocean.OceanCore;
import org.apache.solr.ocean.core.Batch;
import org.apache.solr.ocean.core.TransactionSystem;
import org.apache.solr.ocean.core.Batch.MasterBatch;
import org.apache.solr.ocean.core.Deletes.DeleteByQuery;
import org.apache.solr.ocean.util.Util;
import org.apache.solr.search.QueryParsing;
import org.apache.solr.update.AddUpdateCommand;
import org.apache.solr.update.CommitUpdateCommand;
import org.apache.solr.update.DeleteUpdateCommand;
import org.apache.solr.update.UpdateHandler;

/**
 * Attaches batch to thread. Batch is lost if not committed. A given update
 * needs to commit to see the results.
 * 
 * This is different than the usual Solr update process in which the commit is
 * global.
 * 
 */
public class OceanUpdateHandler extends UpdateHandler {
  private OceanCore oceanCore;
  private TransactionSystem.Category category;
  private ThreadLocal<MasterBatch> currentBatch = new ThreadLocal<MasterBatch>();

  public OceanUpdateHandler(OceanCore oceanCore) {
    super(oceanCore);
    this.oceanCore = oceanCore;
    category = oceanCore.getCategory();
  }

  public MasterBatch getCurrentBatch() throws Exception {
    MasterBatch masterBatch = currentBatch.get();
    if (masterBatch == null) {
      masterBatch = category.createMasterBatch();
      currentBatch.set(masterBatch);
    }
    return masterBatch;
  }

  public int addDoc(AddUpdateCommand cmd) throws IOException {
    try {
      cmd.indexedId = getIndexedId(cmd.doc);
      Document document = cmd.getLuceneDocument(schema);
      MasterBatch batch = getCurrentBatch();
      batch.addDocument(document);
      // TODO: do solr style updates
      return 0;
    } catch (Exception exception) {
      throw Util.asIOException(exception);
    }
  }

  public void delete(DeleteUpdateCommand cmd) throws IOException {
    try {
      Batch batch = getCurrentBatch();
      Term term = idTerm.createTerm(idFieldType.toInternal(cmd.id));
      batch.getDeletes().addTerm(term);
    } catch (Exception exception) {
      throw Util.asIOException(exception);
    }
  }

  public void deleteByQuery(DeleteUpdateCommand cmd) throws IOException {
    try {
      MasterBatch batch = getCurrentBatch();
      Query query = QueryParsing.parseQuery(cmd.query, schema);
      batch.getDeletes().addDeleteByQuery(new DeleteByQuery(query));
    } catch (Exception exception) {
      throw Util.asIOException(exception);
    }
  }

  public void commit(CommitUpdateCommand cmd) throws IOException {
    try {
      MasterBatch batch = getCurrentBatch();
      batch.commit();
      currentBatch.set(null);
    } catch (Exception exception) {
      throw Util.asIOException(exception);
    }
  }

  public void close() throws IOException {
  }

  // ///////////////////////////////////////////////////////////////////
  // SolrInfoMBean stuff: Statistics and Module Info
  // ///////////////////////////////////////////////////////////////////
  public String getName() {
    return getClass().getName();
  }

  public String getVersion() {
    return SolrCore.version;
  }

  public String getDescription() {
    return "Update handler that efficiently directly updates the on-disk main lucene index";
  }

  public Category getCategory() {
    return Category.UPDATEHANDLER;
  }

  public String getSourceId() {
    // return "$Id: DirectUpdateHandler2.java 656826 2008-05-15 20:39:13Z klaas
    // $";
    return "";
  }

  public String getSource() {
    return "";
    // return "$URL:
    // http://svn.apache.org/repos/asf/lucene/solr/trunk/src/java/org/apache/solr/update/DirectUpdateHandler2.java
    // $";
  }

  public URL[] getDocs() {
    return null;
  }

  public NamedList getStatistics() {
    NamedList lst = new SimpleOrderedMap();
    /**
     * lst.add("commits", commitCommands.get()); if (tracker.docsUpperBound > 0) {
     * lst.add("autocommit maxDocs", tracker.docsUpperBound); } if
     * (tracker.timeUpperBound > 0) { lst.add("autocommit maxTime", "" +
     * tracker.timeUpperBound + "ms"); } lst.add("autocommits",
     * tracker.autoCommitCount); lst.add("optimizes", optimizeCommands.get());
     * lst.add("docsPending", numDocsPending.get()); // pset.size() not
     * synchronized, but it should be fine to access. //
     * lst.add("deletesPending", pset.size()); lst.add("adds",
     * addCommands.get()); lst.add("deletesById", deleteByIdCommands.get());
     * lst.add("deletesByQuery", deleteByQueryCommands.get()); lst.add("errors",
     * numErrors.get()); lst.add("cumulative_adds",
     * addCommandsCumulative.get()); lst.add("cumulative_deletesById",
     * deleteByIdCommandsCumulative.get()); lst.add("cumulative_deletesByQuery",
     * deleteByQueryCommandsCumulative.get()); lst.add("cumulative_errors",
     * numErrorsCumulative.get()); lst.add("docsDeleted", numDocsDeleted.get());
     */
    return lst;
  }

  public String toString() {
    return "OceanUpdateHandler" + getStatistics();
  }
}
